package cn.stimd.spring.aop.framework.adapter;

import cn.stimd.spring.aop.Advisor;
import cn.stimd.spring.aop.support.DefaultPointcutAdvisor;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Stimd
 * 项目地址：https://gitee.com/stimd/spring-wheel
 * 公众号：Java编程探微
 */
public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry {
    private final List<AdvisorAdapter> adapters = new ArrayList<>(3);

    /**
     * 默认注册了三个Advice适配器，用于将Advice转换成MethodInterceptor
     */
    public DefaultAdvisorAdapterRegistry() {
        registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
        registerAdvisorAdapter(new AfterReturningAdviceAdapter());
        registerAdvisorAdapter(new ThrowsAdviceAdapter());
    }


    /**
     * 将拦截器包装城Advisor
     * Advisor类型直接返回，MethodInterceptor、Advice的子类都包装成DefaultPointcutAdvisor
     */
    @Override
    public Advisor wrap(Object obj) {
        //如果是Advisor类型，直接强转
        if(obj instanceof Advisor){
            return (Advisor) obj;
        }

        //对MethodInterceptor进行包装
        Advice advice = (Advice) obj;
        if (advice instanceof MethodInterceptor) {
            return new DefaultPointcutAdvisor(advice);
        }

        //对Advice进行包装
        for (AdvisorAdapter adapter : this.adapters) {
            if (adapter.supportsAdvice(advice)) {
                return new DefaultPointcutAdvisor(advice);
            }
        }
        throw new RuntimeException("未知的Advice类型");
    }


    /**
     * 获取Advisor以及适配器默认加载的MethodInterceptor
     */
    @Override
    public MethodInterceptor[] getInterceptors(Advisor advisor) {
        List<MethodInterceptor> interceptors = new ArrayList<>(3);
        Advice advice = advisor.getAdvice();
        //检查Advice是否为MethodInterceptor
        if (advice instanceof MethodInterceptor) {
            interceptors.add((MethodInterceptor) advice);
        }

        //寻找适配Advice的MethodInterceptor
        for (AdvisorAdapter adapter : this.adapters) {
            if (adapter.supportsAdvice(advice)) {
                interceptors.add(adapter.getInterceptor(advisor));
            }
        }
        if (interceptors.isEmpty()) {
            throw new RuntimeException("没有找到MethodInterceptor");
        }
        return interceptors.toArray(new MethodInterceptor[interceptors.size()]);
    }


    @Override
    public void registerAdvisorAdapter(AdvisorAdapter adapter) {
        this.adapters.add(adapter);
    }
}
